<template>
  <div class="gc-table-component">
    <div class="table-content">
      <div class="table-content-search" v-if="showSearch || $slots['btn-group']">
        <div class="search-keyword-modal">
          <el-input
            v-if="showSearch"
            class="gc-table-search-input"
            v-model="searchKeyWords"
            :placeholder="searchPlaceholder"
            clearable
            @keyup.enter.stop.prevent="handleSearch">
            <template #suffix>
              <el-icon style="cursor: pointer;" @click="handleSearch" class="el-input__icon"><Search /></el-icon>
            </template>
          </el-input>
          <div class="search-right" v-if="showFilter">
            <GcAdvanceSearch
              :defaultFilter="defaultFilter"
              :filterList="filterList"
              @reset-fileds="resetSearchFileds"
              @get-search-params="getAdvanceQueryParams"></GcAdvanceSearch>
          </div>
        </div>
        <div class="header-operate">
          <div class="operate-block" v-if="$slots['btn-group']">
            <slot name="btn-group"></slot>
          </div>
        </div>
      </div>
      <el-table
        ref="customTableRef"
        :row-key="rowKey"
        :data="tableData"
        :stripe="stripe"
        :border="border"
        :height="height"
        :show-header="showHeader"
        :max-height="maxHeight"
        :default-sort="defaultSort"
        :table-layout="tableLayout"
        :highlight-current-row="highlightCurrentRow"
        :row-class-name="rowClassName"
        :tooltip-options="{ placement: 'top-end' }"
        :span-method="spanMethod"
        :default-expand-all="defaultExpanAll"
        @selection-change="handleSelectionChange"
        @sort-change="handleSortChange"
        @row-click="handleRowClick">
        <el-table-column v-if="showSelection" fixed="left" type="selection" width="40" />
        <el-table-column
          v-for="item in columns"
          :key="item.key"
          :prop="item.key"
          :label="item.name"
          :width="item.width"
          :min-width="item.minWidth"
          :fixed="item.fixed"
          :show-overflow-tooltip="item.showOverflowTooltip"
          :sortable="item.sortable"
          :align="item.align || 'center'">
          <!-- 自定义表头 -->
          <template #header v-if="item.slotHead && $slots[item.slotHead]">
            <slot :name="item.slotHead"></slot>
          </template>

          <!-- 自定义列模板 -->
          <template #default="{ row, $index }">
            <slot
              v-if="item.slot && $slots[item.slot]"
              :name="item.slot"
              :row="row"
              :$index="$index"></slot>
            <span v-else>{{ !isBlank(row[item.key]) ? row[item.key] : '--' }}</span>
          </template>
        </el-table-column>
        <template #empty>
          <div class="custom-empty-table">
            <img src="@/assets/images/empty.png" alt="">
            <p>{{ emptyText }}</p>
          </div>
        </template>
      </el-table>
    </div>
    <div class="pagination-modal" v-if="showPage">
      <el-pagination
        v-model:current-page="pageNo"
        layout="total, prev, pager, next, jumper"
        background
        :page-size="pagination.pageSize"
        :total="pagination.total"
        @current-change="handleCurrentChange"
      />
    </div>
  </div>
</template>

<script setup lang="ts" name="GcTable">
import { ref, type PropType, computed, watch } from 'vue'
import type { Columns, Pagination } from './type'
import type { TableInstance, Sort } from 'element-plus'
import { Search } from '@element-plus/icons-vue'
import type { FilterItem } from '@/components/gloabComponents/GcAdvanceSearch/type'
import { isBlank } from '@/utils'

const props = defineProps({
  rowKey: {
    type: String,
    default: 'id'
  },
  tableData: {
    type: Array,
    default: () => []
  },
  columns: {
    type: Array as PropType<Columns[]>,
    default: () => {
      return []
    }
  },
  tableLayout: {
    type: String as PropType<'auto' | 'fixed'>,
    default: 'fixed'
  },
  searchPlaceholder: {
    type: String,
    default: '请输入搜索关键字'
  },
  showSelection: {
    type: Boolean,
    default: true
  },
  stripe: {
    type: Boolean,
    default: false
  },
  defaultExpanAll: {
    type: Boolean,
    default: false
  },
  border: {
    type: Boolean,
    default: false
  },
  rowClassName: {
    type: Function as PropType<any>
  },
  showHeader: {
    type: Boolean,
    default: true
  },
  height: {
    type: Number
  },
  maxHeight: {
    type: Number
  },
  highlightCurrentRow: {
    type: Boolean,
    default: false
  },
  defaultSort: {
    type: Object as PropType<Sort>
  },
  emptyText: {
    type: String,
    default: '暂无数据'
  },
  spanMethod: {
    type: Function as PropType<any>
  },
  pagination: {
    type: Object as PropType<Pagination>,
    default: () => {
      return {
        pageNo: 1,
        pageSize: 10,
        total: 0,
        pages: 0
      }
    }
  },
  showPage: {
    type: Boolean,
    default: true
  },
  searchKeywords: {
    type: String,
    default: ''
  },
  showSearch: {
    type: Boolean,
    default: true
  },
  showFilter: {
    type: Boolean,
    default: true
  },
  filterList: {
    type: Array as PropType<Array<FilterItem>>,
    default: () => {
      return []
    }
  },
  defaultFilter: {
    type: Object,
    default: () => {
      return {}
    }
  }
})

const emits = defineEmits(
  [
    'selection-change',
    'sort-change',
    'filter-change',
    'row-click',
    'current-change',
    'search',
    'get-search-params',
    'reset-fileds',
    'update:searchKeywords'
  ]
)

const searchKeyWords = ref(props.searchKeywords)

watch(() => props.searchKeywords, val => {
  searchKeyWords.value = val
})

watch(() => searchKeyWords.value, val => {
  emits('update:searchKeywords', val)
})

const customTableRef = ref<null | TableInstance>(null)

const pageNo = computed(() => {
  return props.pagination.pageNo
})

function getAdvanceQueryParams (searchParams: any) {
  emits('get-search-params', searchParams)
}

function resetSearchFileds (searchParams: any) {
  emits('reset-fileds', searchParams)
}

function handleSelectionChange (selection: []) {
  emits('selection-change', selection)
}

function handleSortChange ({ column, prop, order } : {
  column: any;
  prop: string;
  order: string;
}) {
  emits('sort-change', { column, prop, order })
}

function handleRowClick (
  row: Record<string | number | symbol, any>,
  column: any,
  event: Event) {
  emits('row-click', row, column, event)
}

function handleCurrentChange (val: number) {
  emits('current-change', val)
}

function handleSearch () {
  emits('search')
}

function clearSelection () {
  customTableRef.value && customTableRef.value.clearSelection()
}

function getSelectionRows () {
  customTableRef.value && customTableRef.value.getSelectionRows()
}

function toggleRowSelection (row: any, selected: boolean) {
  customTableRef.value && customTableRef.value.toggleRowSelection(row, selected)
}

function toggleAllSelection () {
  customTableRef.value && customTableRef.value.toggleAllSelection()
}

function setCurrentRow (row: any) {
  customTableRef.value && customTableRef.value.setCurrentRow(row)
}

function clearSort () {
  customTableRef.value && customTableRef.value.clearSort()
}

function sort (prop: string, order: string) {
  customTableRef.value && customTableRef.value.sort(prop, order)
}

function toggleRowExpansion (row: any, expanded: boolean) {
  customTableRef.value && customTableRef.value.toggleRowExpansion(row, expanded)
}

defineExpose({
  customTableRef,
  clearSelection,
  getSelectionRows,
  toggleRowSelection,
  toggleAllSelection,
  setCurrentRow,
  clearSort,
  sort,
  toggleRowExpansion
})
</script>

<style scoped lang="scss">
.gc-table-component {
  height: 100%;
  display: flex;
  flex-direction: column;
  border-radius: 4px;
  background: #fff;
  .header-operate {
    box-sizing: border-box;
    display: flex;
    justify-content: flex-start;
  }
  .table-content {
    flex: 1;
    height: 0;
    display: flex;
    flex-direction: column;
    &-search {
      display: flex;
      height: 52px;
      border-bottom: 1px solid #f0f0f0;
      padding: 0 12px;
      justify-content: space-between;
      align-items: center;
      .search-keyword-modal {
        display: flex;
        align-items: center;
        .gc-table-search-input {
          width: 320px;
        }
        .search-right {
          margin-left: 16px;
        }
      }
    }

    :deep(.el-table) {
      flex: 1;
      height: 0;
      .el-table__inner-wrapper {
        &::before {
          display: none;
        }
      }
      .el-table__cell {
        padding: 8px 0;
      }
      .el-table__header-wrapper {
        .el-table__header {
          thead {
            font-weight: 600;
          }
        }
      }
      .descending .sort-caret.descending {
        border-top-color: #567ced;
      }
      .ascending .sort-caret.ascending {
        border-bottom-color: #567ced;
      }
      .sort-caret.ascending {
        border-bottom-color: #acc2fd;
      }
      .sort-caret.descending {
        border-top-color: #acc2fd;
      }
      .el-table__column-filter-trigger i {
        color: #acc2fd;
      }
      .el-table__empty-block {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        .custom-empty-table {
          text-align: center;
          img {
            width: 220px;
            display: block;
            margin: 0 auto;
          }
          p {
            color: #4c4c4c;
            line-height: 32px;
            margin-top: 8px;
          }
        }
      }
    }
  }
  .pagination-modal {
    display: flex;
    justify-content: flex-end;
    height: 50px;
    align-items: center;
    padding: 0 12px;
    border-top: 1px solid #f1f1f1;
  }
}
</style>
